from matrix import *
import random

VIVO = 1
MUERTO = 0

def main():
    
    filas = int(raw_input("Ingrese las filas: "))
    columnas = int(raw_input("Ingrese las columnas: "))
    
    # Genero la matriz inicial
    #matrix  = initial_matrix(filas, columnas)
    #matrix  = read_from_file(filas, columnas)
    matrix = Matrix(filas, columnas)
    
    input = raw_input('Ingrese celda de explosion (i,j) Ejemplo "(3,4) Enter" \n: ')
    input = input.strip(' ()')
    input = input.split(',')
    i = int(input[0].strip(' '))
    j = int(input[1].strip(' '))
    value = int(raw_input('Ingrese Presion de explosion: '))
    celda = matrix.get_cell(i,j)
    celda.pressure = value
    celda.new_pressure = value
    print matrix
    
    end = False
    while not end:
        end = raw_input('Salir? (s/n) ')[0] == 's'
        #matrix = update(matrix)
        rules_pressure(matrix)
        update_pressure(matrix)
        print matrix
        
    
    
    return 0

def read_from_file( matrix ):
    
    file = raw_input('Nombre de archivo input: ')
    f = open(file, 'r')
    
    for line in f.readlines():
        # fila, columna
        data = line.strip(' ')
        data = data.split(',')
        fila = int(data[0])
        columna = int(data[1])
        matrix.set_value(fila,columna,VIVO)
        
def initial_matrix( matrix ):

    end = False
    while not end:
        input = raw_input('Ingrese celda (i,j) Ejemplo "(3,4) Enter" \n: ')
        input = input.strip(' ()')
        input = input.split(',')
        i = int(input[0].strip(' '))
        j = int(input[1].strip(' '))
        value = int(raw_input('Ingrese valor: '))
        matrix.set_value(i,j,value)
        #c = matrix.get_cell(i,j)
        #c.pressure = value
        #c.new_pressure = value
        end = raw_input('Terminar ingreso de datos? (s/n) ')[0]=='s'
    
    #return matrix

def fill_random( matrix ):
    
    for i in range(1,matrix.rows+1):
        for j in range(1,matrix.cols+1):
            matrix.set_value(i,j, random.choice([VIVO, MUERTO]))
            
    
def update(matrix):
    new = Matrix(matrix.rows, matrix.cols)
    
    
    for i in range(1, matrix.rows+1):
        for j in range(1, matrix.cols+1):
            vivir = rules(matrix, i, j)
            if vivir:
                new.set_value(i,j, VIVO)
                
    return new

def rules(matrix, row, col):
    vivir = False
    alive = matrix.alive(row,col)
    vecinos = len(matrix.vecinos(row,col)) 
    
    if vecinos < 2 and alive:
        #print "Rule 1 antes VIVA=%s ahora VIVA Celda (%s,%s)" %(alive, row,col)
        vivir = False
    elif vecinos > 3 and alive:
        #print "Rule 2 antes VIVA=%s ahora VIVA Celda (%s,%s)" %(alive, row,col)
        vivir = False
    elif (2 == vecinos or vecinos   == 3) and alive:
        #print "Rule 3 antes VIVA=%s ahora VIVA Celda (%s,%s)" %(alive, row,col)
        vivir = True
    elif vecinos == 3 and not alive:
        #print "Rule 4 antes VIVA=%s ahora VIVA Celda (%s,%s)" %(alive, row,col)
        vivir = True
    
    return vivir

def rules_pressure(matrix):
    
    for i in range(1, matrix.rows+1):
        for j in range(1, matrix.cols+1):
            
            # Obtengo los vecinos de la celda
            vecinos = matrix.vecinos(i,j)
            
            for vecino in vecinos:
                
                # Calculo la diferencia de presion
                dpres = matrix.get_value(i,j) - vecino.get_pressure()
                
                '''Calculamos el flujo como una fraccion de la diferencia de presion.
                0.12 es un numero magico que indica la fluidez del medio. Un valor muy chico
                hace que la presion se propague mas lentamente.
                Usamos la funcion clamp para evitar valores negativos en el nodo.
                Se hace que el flujo no produsca una presion negativa'''
                #flow=clamp(0.12*dpres, node.pressure/4.0, -neight.pressure/4.0)
                flow=clamp(0.12*dpres, matrix.get_value(i,j)/8.0, -vecino.get_pressure()/8.0)
                
                #Actualizamos la presion (usando new_pressure en lugar de pressure) substrayendo
                #presion del nodo actual y agregandola a su vecino. Un flujo negativo implica
                #que la presion del nodo actual aumenta y la del vecino disminuye.
                
                #node.new_pressure -= flow
                matrix.get_cell(i,j).new_pressure -= flow
                
                #neight.new_pressure += flow
                vecino.new_pressure += flow

    return 

def update_pressure(matrix):
    
    for i in range(1, matrix.rows+1):
        for j in range(1, matrix.cols+1):
            matrix.get_cell(i,j).update()
            
    return 

def clamp(value, max, min):
        '''
        Funcion clamp, devuelve value si value esta entre min y max, devuelve min o max si no.
        '''
        if value<min:
            return min
        if value>max:
            return max
        return value

if __name__ == '__main__':
    main()
